﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GoodTrader.GTDownload
{
    public class CpCmeDownloader : CpDownLoader
    {
        public CpCmeDownloader(CpDownLoadManager aDownManager, CpFutureData aData)
            : base(aDownManager)
        {
            mData = aData;
            m_FutChartFetcher.Received += new CPSYSDIBLib._ISysDibEvents_ReceivedEventHandler(OnReceived);
        }
        private short mCycle = 1;
        public short Cycle
        {
            get { return mCycle; }
            set { mCycle = value; }
        }

        private long mStartDate = 0;
        public long StartDate
        {
            get { return mStartDate; }
            set { mStartDate = value; }
        }
        private long mEndDate = 0;
        public long EndDate
        {
            get { return mEndDate; }
            set { mEndDate = value; }
        }

        // 요청구분 : 1 - 기간별, 2 - 개수 데이터
        private char mReqType = '2';
        public char ReqType
        {
            get { return mReqType; }
            set { mReqType = value; }
        }
        // 요청 개수
        private uint mReqCount = 10;
        public uint ReqCount
        {
            get { return mReqCount; }
            set { mReqCount = value; }
        }
        // 차트 구분 : 'T' - 틱, 'S' - 초, 'm' - 분, 'M' - 월, 'W' - 주, 'D' - 일
        private char mChartType = 'm';
        public char ChartType
        {
            get { return mChartType; }
            set { mChartType = value; }
        }
        private double[] arrVal = new double[GTGlobal.MaxDownloadCount];

        // 주간 선물 차트 데이터를 가져오는 객체
        private CPSYSDIBLib.FutOptChartClass m_FutChartFetcher = new CPSYSDIBLib.FutOptChartClass();
        private CpFutureData mData = null; // new CpFutureData();
        public CpFutureData Data
        {
            get { return mData; }
            set { mData = value; }
        }

        // 처음에는 블로킹 모드로 데이터를 정해진 갯수만큼 가져온다.
        public void BlockDownload()
        {
            object code = m_CpFutureCode.GetData(0, 0);
            int[] fields = new int[] { 0, 1, 2, 3, 4, 5, 6, 8, 27, 29 };
            m_FutChartFetcher.SetInputValue(0, code);
            m_FutChartFetcher.SetInputValue(1, mReqType);
            m_FutChartFetcher.SetInputValue(2, mEndDate);
            m_FutChartFetcher.SetInputValue(3, mStartDate);
            m_FutChartFetcher.SetInputValue(4, GTGlobal.MaxDownloadCount);
            m_FutChartFetcher.SetInputValue(5, fields);
            m_FutChartFetcher.SetInputValue(6, mChartType);
            m_FutChartFetcher.SetInputValue(7, mCycle);
            m_FutChartFetcher.SetInputValue(11, '1'); // '0' : 주간선물, '1' : 야간선물, '2' : 주간선물 + 야간 선물

            // 데이터 수신 요청을 한다.
            try
            {
                // 데이터 수신 요청을 한다.
                m_FutChartFetcher.BlockRequest();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }


            object dataCount = m_FutChartFetcher.GetHeaderValue(3);

            for (int i = Convert.ToInt32(dataCount) - 1, j = 0; i > -1; i--, j++)
            {
                mData.Date[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(0, i)); // 날짜
                mData.Time[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(1, i)); // 시간
                mData.Open[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(2, i).ToString()); // 시가
                mData.High[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(3, i).ToString()); // 고가
                mData.Low[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(4, i).ToString()); // 저가
                mData.Close[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(5, i).ToString()); // 종가
                mData.Amount[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(7, i)); // 거래량
                mData.UnSet[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(8, i)); // 미결제약정
                mData.Basis[j] = Convert.ToDouble(m_FutChartFetcher.GetDataValue(9, i)); // 베이시스
            }

            // 여기서 증권사 시간을 차트 시간으로 변환해 준다.
            GTGlobal.StockTimeToChartDirectorTime(mData.Date, mData.Time, mData.cTime);
        }

        // 다운로드 함수로 상속 클래스의 함수를 재정의 한다.
        public override void Download()
        {
            // 이미 다운 받은 상태이므로 먼저 베이스 클래스의 함수를 실행한다.
            base.Download();
            // 여기서 다운로드 할 내용을 실행한다.
            //System.Windows.Forms.MessageBox.Show("FutOptDownStarted");

            object code = m_CpFutureCode.GetData(0, 0);
            int[] fields = new int[] { 0, 1, 2, 3, 4, 5, 6, 8, 27, 29 };
            m_FutChartFetcher.SetInputValue(0, code); // 종목 코드
            m_FutChartFetcher.SetInputValue(1, mReqType); // 요청구분 : 1 - 기간별, 2 - 개수 데이터
            m_FutChartFetcher.SetInputValue(2, mEndDate); // 요청 종료일
            m_FutChartFetcher.SetInputValue(3, mStartDate); // 요청 시작일
            m_FutChartFetcher.SetInputValue(4, mReqCount); // 요청 개수
            m_FutChartFetcher.SetInputValue(5, fields); // 필드값
            m_FutChartFetcher.SetInputValue(6, mChartType); // 차트 구분 : T - 틱, S - 초, m - 분, M - 월, W - 주, D - 일
            m_FutChartFetcher.SetInputValue(7, mCycle); // 주기
            m_FutChartFetcher.SetInputValue(11, '1'); // '0' : 주간선물, '1' : 야간선물, '2' : 주간선물 + 야간 선물

            // 데이터 수신 요청을 한다.
            try
            {
                // 데이터 수신 요청을 한다.
                m_FutChartFetcher.Request();
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        /**
         * @breif 이 함수는 증권사 데이터를 받았을 때 데이터를 저장해 준다.
         * @remark 증권사 데이터의 마지막 데이터를 신뢰할 수 없기에 맨 마지막 데이터를 비교하지 않고 맨마지막 이전 데이터를 비교값으로 한다.
         */
        public override void OnReceived()
        {
            // 베이스 클래스의 함수를 먼저 호출한다. 여기서 이벤트가 다시 설정된다. 
            base.OnReceived();

            if (mData == null)
                return;

            object dataCount = m_FutChartFetcher.GetHeaderValue(3);
            int nCount = Convert.ToInt32(dataCount);
            // 데이터가 최소한 2개이상 받았을 때만 다음으로 진행된다.
            // 마지막 다음 시간을 비교하기 위해서이다.
            if (nCount <= 1)
                return;

            double curDate = Convert.ToDouble(m_FutChartFetcher.GetDataValue(0, 0)); // 날짜
            double curTime = Convert.ToDouble(m_FutChartFetcher.GetDataValue(1, 0)); // 시간
            double curOpen = Convert.ToDouble(m_FutChartFetcher.GetDataValue(2, 0).ToString()); // 시가
            double curHigh = Convert.ToDouble(m_FutChartFetcher.GetDataValue(3, 0).ToString()); // 고가
            double curLow = Convert.ToDouble(m_FutChartFetcher.GetDataValue(4, 0).ToString()); // 저가
            double curClose = Convert.ToDouble(m_FutChartFetcher.GetDataValue(5, 0).ToString()); // 종가
            double curAmount = Convert.ToDouble(m_FutChartFetcher.GetDataValue(7, 0)); // 거래량
            double curUnSet = Convert.ToDouble(m_FutChartFetcher.GetDataValue(8, 0)); // 미결제약정
            double curBasis = Convert.ToDouble(m_FutChartFetcher.GetDataValue(9, 0)); // 베이시스

            double befDate = Convert.ToDouble(m_FutChartFetcher.GetDataValue(0, 1)); // 날짜
            double befTime = Convert.ToDouble(m_FutChartFetcher.GetDataValue(1, 1)); // 시간
            double befOpen = Convert.ToDouble(m_FutChartFetcher.GetDataValue(2, 1).ToString()); // 시가
            double befHigh = Convert.ToDouble(m_FutChartFetcher.GetDataValue(3, 1).ToString()); // 고가
            double befLow = Convert.ToDouble(m_FutChartFetcher.GetDataValue(4, 1).ToString()); // 저가
            double befClose = Convert.ToDouble(m_FutChartFetcher.GetDataValue(5, 1).ToString()); // 종가
            double befAmount = Convert.ToDouble(m_FutChartFetcher.GetDataValue(7, 1)); // 거래량
            double befUnSet = Convert.ToDouble(m_FutChartFetcher.GetDataValue(8, 1)); // 미결제약정
            double befBasis = Convert.ToDouble(m_FutChartFetcher.GetDataValue(9, 1)); // 베이시스
            
            // 마지막 인덱스를 가져온다.
            int endIndex = mData.Time.Length - 1;

            double beforeTime = mData.Time[endIndex - 1];

            //Console.WriteLine("future beforetime ->" + beforeTime.ToString() + "::" +  "befTime ->" + befTime.ToString());
            //Console.WriteLine("curOpen" + curOpen.ToString());
            //Console.WriteLine("curClose" + curClose.ToString());
            //Console.WriteLine("curHigh" + curHigh.ToString());
            //Console.WriteLine("curLow" + curLow.ToString());

            // 마지막 봉 이전 시간과 같아졌을 때 데이터를 좌측으로 밀어주고 새로운 데이터를 기록해 준다.
            if (befTime != beforeTime)
            {
                GTGlobal.ShiftArrayVal(curDate, befDate, mData.Date, arrVal);
                GTGlobal.ShiftArrayVal(curTime, befTime, mData.Time, arrVal);
                GTGlobal.ShiftArrayVal(curOpen, befOpen, mData.Open, arrVal);
                GTGlobal.ShiftArrayVal(curHigh, befHigh, mData.High, arrVal);
                GTGlobal.ShiftArrayVal(curLow, befLow, mData.Low, arrVal);
                GTGlobal.ShiftArrayVal(curClose, befClose, mData.Close, arrVal);
                GTGlobal.ShiftArrayVal(curAmount, befAmount, mData.Amount, arrVal);
                GTGlobal.ShiftArrayVal(curUnSet, befUnSet, mData.UnSet, arrVal);
                GTGlobal.ShiftArrayVal(curBasis, befBasis, mData.Basis, arrVal);

                // 증권사 시간을 차트시간으로 변환해 준다.
                double cCurTime = 0.0;
                // 현재 시간을 차트 시간으로 변환한다.
                GTGlobal.StockTimeToChartDirectorTime(curDate, curTime, ref cCurTime);
                // 증권사 시간을 차트시간으로 변환해 준다.
                double cBefTime = 0.0;
                // 현재 시간을 차트 시간으로 변환한다.
                GTGlobal.StockTimeToChartDirectorTime(curDate, curTime, ref cBefTime);
                GTGlobal.ShiftArrayVal(cCurTime, cBefTime, mData.cTime, arrVal);
            }
            else
            {
                mData.Date[endIndex] = curDate;
                mData.Time[endIndex] = curTime;
                // 증권사 시간을 차트시간으로 변환해 준다.
                double cTime = 0.0;
                // 현재 시간을 차트 시간으로 변환한다.
                GTGlobal.StockTimeToChartDirectorTime(curDate, curTime, ref cTime);
                // 차트 시간에 넣어준다.
                mData.cTime[endIndex] = cTime;
                mData.Open[endIndex] = curOpen;
                mData.High[endIndex] = curHigh;
                mData.Low[endIndex] = curLow;
                mData.Close[endIndex] = curClose;
                mData.Amount[endIndex] = curAmount;
                mData.UnSet[endIndex] = curUnSet;
                mData.Basis[endIndex] = curBasis;
            }
        }
    }
}
